package com.woniuxy.movie.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.json.JSONUtil;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniuxy.movie.commons.core.model.Result;
import com.woniuxy.movie.commons.web.config.AlipayConfiguration;
import com.woniuxy.movie.commons.web.model.PageInfo;
import com.woniuxy.movie.commons.web.model.PagePayDto;
import com.woniuxy.movie.commons.web.util.AlipayUtil;
import com.woniuxy.movie.commons.web.util.OSSUtil;
import com.woniuxy.movie.commons.web.util.StateData;
import com.woniuxy.movie.order.client.ProductClient;
import com.woniuxy.movie.order.client.dto.SessionInfoDto;
import com.woniuxy.movie.order.client.dto.TicketInfoDto;
import com.woniuxy.movie.order.dao.OrderInfoMapper;
import com.woniuxy.movie.order.dto.HandlerOrderDto;
import com.woniuxy.movie.order.dto.OrderInfoDto;
import com.woniuxy.movie.order.dto.PageOrderInfoDto;
import com.woniuxy.movie.order.exception.OrderException;
import com.woniuxy.movie.order.form.CreateOrderForm;
import com.woniuxy.movie.order.form.orderinfo.PagePayForm;
import com.woniuxy.movie.order.form.ticket.TicketSaledForm;
import com.woniuxy.movie.order.model.OrderInfo;
import com.woniuxy.movie.order.model.OrderLog;
import com.woniuxy.movie.order.service.OrderInfoService;
import com.woniuxy.movie.order.util.QRUtil;
import com.woniuxy.movie.order.util.RedisUtil;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 电影票订单详情表 服务实现类
 * </p>
 *
 * @author 刘存益
 * @since 2023年11月17日
 */
@Service
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {


    @Autowired
    private ProductClient pc;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private AlipayUtil alipayUtil;
    @Autowired
    private AlipayConfiguration alipayConfiguration;

    @Autowired
    private OSSUtil ossUtil;

    /**
     * 下单业务
     * @param form
     * @return
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    //@Transactional(rollbackFor = Exception.class)
    public OrderInfoDto createOrder(CreateOrderForm form) {
        //前置判断
        Result<List<TicketInfoDto>> result = pc.byTicketIds(form.getTicketIds());
        //判断查找电影票的过程中是否出错
        if (result.getCode()!=200) {
            throw new OrderException(result.getCode(),result.getMsg());
        }
        //电影票是否存在
        List<TicketInfoDto> tids = result.getData();
        if (tids == null || tids.size()<=0 || tids.size()!= form.getTicketIds().size()) {
            throw new OrderException(1001,"下单的票务数据不存在");
        }
        Integer sessionId = tids.get(0).getSessionId();
        List<String> tickets = new ArrayList<>();
        //购买的电影票是否在同一个场次
        for (TicketInfoDto td : tids) {
            if (td.getSessionId()!=sessionId) {
                throw new OrderException(1002,"购买的票务不在一个场次");
            }
            if (td.getTicketState()!= StateData.TICKET_STATE_NORMAL) {
                throw new OrderException(1003,td.getSeatRow()+"行"+td.getSeatCol()+"座票务不能购买");
            }
            tickets.add(td.getSeatRow()+"排"+td.getSeatCol()+"座");
        }
        //判定场次是否可以正常购买
        Result<SessionInfoDto> sessionResult = pc.bySessionId(sessionId);
        if (sessionResult.getCode()!=200) {
            throw new OrderException(result.getCode(),result.getMsg());
        }
        SessionInfoDto sid = sessionResult.getData();
        if (sid==null) {
            throw new OrderException(1004,"购买的场次不存在或已下架");
        }
        Long indexTime = System.currentTimeMillis();
        Long startTime = DateUtil.parse(sid.getSessionStartTime(), "yyyy-MM-dd HH:mm:ss").getTime();
        System.out.println(startTime);
        if (indexTime>startTime) {
            sid.setSessionState(StateData.SESSION_STATE_DISABLED);
            pc.saveSession(sid);
            throw new OrderException(1005,"购买的场次不存在或已下架");
        }
        //通过数据自带的update锁区改变需要购买票务的状态，修改成功就继续下单，修改失败就回滚事务
        Result<Integer> lockResult = pc.saveTicketLock(form.getTicketIds());
        if (lockResult.getCode()!=200) {
            throw new OrderException(lockResult.getCode(),lockResult.getMsg());
        }
        if (form.getTicketIds().size()!=lockResult.getData()) {
            throw new OrderException(1006,"有票务已经被购买");
        }
        //生成订单数据保存数据库
        //使用雪花算法生成订单编号
        String orderId = new Snowflake(1, 1).nextIdStr();
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setOrderId(orderId);
        orderInfo.setHallName(sid.getHallName());
        orderInfo.setMovieName(sid.getMovieName());
        orderInfo.setMovieTime(sid.getMovieTime());
        orderInfo.setOrderNum(null);
        orderInfo.setOrderQr(null);
        orderInfo.setOrderTime(DateUtil.format(new Date(System.currentTimeMillis()),"yyyy-MM-dd HH:mm:ss"));
        orderInfo.setOrderUser(form.getPhone());
        orderInfo.setOrderSeats(JSONUtil.parse(tickets).toString());
        orderInfo.setSessionEndTime(sid.getSessionEndTime());
        orderInfo.setSessionStartTime(sid.getSessionStartTime());
        orderInfo.setOrderPrice(sid.getSessionPrice());
        BigDecimal all = sid.getSessionPrice().multiply(new BigDecimal(form.getTicketIds().size()));
        orderInfo.setOrderAllprice(all);
        orderInfo.setOrderState(StateData.ORDER_STATE_NOPAY);
        save(orderInfo);
        HandlerOrderDto handlerOrderDto = new HandlerOrderDto();
        handlerOrderDto.setOrderId(orderId);
        handlerOrderDto.setTicketIds(form.getTicketIds());
        rabbitTemplate.convertAndSend("order-delay",handlerOrderDto);
        //生成日志
        OrderLog orderLog = new OrderLog();
        orderLog.setOrderId(orderId);
        orderLog.setLogTime(orderInfo.getOrderTime());
        orderLog.setLogUser(orderInfo.getOrderUser());
        orderLog.setLogDesc(orderInfo.getOrderUser()+"用户在"+orderInfo.getOrderTime()+"下单成功"+form.getTicketIds().size()+"张在"+orderInfo.getHallName()+orderInfo.getSessionStartTime()+"时间播放的"+orderInfo.getMovieName()+"电影票");
        rabbitTemplate.convertAndSend("create-orderLog",orderLog);
        //将订单ID作为键票务ID作为值保存到redis内
        redisUtil.saveObject(orderId,form.getTicketIds());
        //生成数据返回
        OrderInfoDto oid = BeanUtil.toBean(orderInfo, OrderInfoDto.class);
        oid.setSeats(tickets);
        return oid;
    }

    /**
     * 分页查询所有订单
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public PageInfo selectPageOrders(Integer pageNum, Integer pageSize) {
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        Page<OrderInfo> page = new Page<OrderInfo>(pageNum == null ? 1 : pageNum, pageSize == null ? 5 : pageSize);
        orderInfoMapper.selectPage(page, wrapper);
        System.out.println(page.getTotal());
        PageInfo pageInfo = BeanUtil.toBean(page, PageInfo.class);
        List<PageOrderInfoDto> pageOrderInfoDtos = new ArrayList<>();
        for (OrderInfo orderInfo : page.getRecords()) {
            PageOrderInfoDto pageOrderInfoDto = BeanUtil.toBean(orderInfo, PageOrderInfoDto.class);
            pageOrderInfoDtos.add(pageOrderInfoDto);
        }
        pageInfo.setPages(page.getPages());
        pageInfo.setList(pageOrderInfoDtos);
        System.out.println(pageInfo);
        return pageInfo;
    }

    /**
     * 查询订单详情信息
     * @param orderId
     * @return
     */
    @Override
    public OrderInfoDto findSingleOrder(String orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if (orderInfo==null) {
            throw new OrderException(1007,"该订单不存在,查询详情失败");
        }
        OrderInfoDto orderInfoDto = BeanUtil.toBean(orderInfo, OrderInfoDto.class);
        orderInfoDto.setSeats(new ArrayList<>(JSONUtil.parseArray(orderInfo.getOrderSeats()).toList(String.class)));
        return orderInfoDto;
    }

    /**
     * 发起支付
     * @param form
     * @return
     * @throws Exception
     */
    @Override
    public String pagePay(PagePayForm form) throws Exception {
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id", form.getOrderId());
        wrapper.eq("order_user", form.getUserName());
        OrderInfo orderInfo = orderInfoMapper.selectOne(wrapper);
        if (orderInfo == null) {
            throw new OrderException(1008,"该订单不存在");
        }
        if (orderInfo.getOrderState() != StateData.ORDER_STATE_NOPAY) {
            throw new OrderException(1009,"该订单已支付或已取消");
        }
        PagePayDto param = BeanUtil.toBean(form, PagePayDto.class);
        //设置参数
        param.setMoney(orderInfo.getOrderAllprice().doubleValue());
        param.setSubject("IKUN影城");
        param.setNotifyUrl("http://exqkyc.natappfree.cc/order/orderInfo/notify");//异步路径
        param.setBody("电影票订单支付");
        String page = alipayUtil.pagePay(param);
        return page;
    }

    /**
     * 支付宝回调修改订单状态以及其它
     * @param params
     * @throws Exception
     */
    @Override
    public void handlerOrder(Map<String, String> params) throws Exception{
        //在异步回调业务层验签 防止伪造请求
        boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayConfiguration.getAlipayPublicKey(), "utf-8", "RSA2"); //调用SDK验证签名
        if (!signVerified) {
            throw new OrderException(1009,"签名错误");
        }
        //验签通过
        //取出订单编号
        String orderId = params.get("out_trade_no");
        String tradeStatus = params.get("trade_status");
        String payDate = params.get("gmt_payment");
        if ("TRADE_SUCCESS".equals(tradeStatus)) {
            //判断当前的订单状态是否是未支付
            OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
            if (orderInfo.getOrderState()== StateData.ORDER_STATE_NOPAY) {
                //修改订单状态
                orderInfo.setOrderState(StateData.ORDER_STATE_PAYED);
                orderInfo.setOrderPayTime(payDate);
                //生成二维码
                InputStream qr = QRUtil.createQR(orderInfo.getOrderId(),"jpg","https://liucunyi.oss-cn-chengdu.aliyuncs.com/4b25ae6f100b478483c73facc9a07269.jpg");
                String fileName = UUID.randomUUID().toString().replaceAll("-","")+".jpg";
                //二维码上传到oss
                String path = ossUtil.uploadFile(qr,fileName,"liucunyi");
                //返回oss中的路径保存到数据库
                orderInfo.setOrderQr(path);
                //生成取票码
                // 取时间戳后8位作为生成的数字
                Long number = System.currentTimeMillis() % 100000000;
                orderInfo.setOrderNum(number.toString());
                orderInfoMapper.updateById(orderInfo);
                //修改票务状态以及其它信息
                TicketSaledForm ticketSaledForm = new TicketSaledForm();
                ticketSaledForm.setTicketTime(payDate);
                ticketSaledForm.setTicketUser(orderInfo.getOrderUser());
                //从redis中将ticketIds取出来
                Set<Integer> ticketIds = (Set<Integer>) redisUtil.getObject(orderId);
                ticketSaledForm.setIds(ticketIds);
                Result<Integer> saledResult = pc.saveTicketSaled(ticketSaledForm);
                if (saledResult.getCode()!=200) {
                    throw new OrderException(saledResult.getCode(),saledResult.getMsg());
                }
                if (ticketIds.size()!=saledResult.getData()) {
                    throw new OrderException(1006,"有票务修改已售失败");
                }
                //将ticketIds从redis中删除
                redisUtil.delObject(orderId);
            }
        }
    }


}
